﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

/**
 * @file GameObjectList
 * 
 * @author LeonXie
 * */

namespace Catsland.Core {
    /**
     * @brief every scene holds a GameObjectList, storing the list of gameObject
     * 
     * adding or removing item should be performed ascyn while gaming is running
     * */
    public class GameObjectList : UniqueList<GameObject> {

        // store the gameObjects waiting to be removed
        List<GameObject> m_removeList;
        // store the gameObjects waiting to be added
        List<GameObject> m_addList;

        /**
         * @brief add gameObject to list
         * 
         * the gameObject will be added to list in next adding phase
         * */
        public override void AddItem(string guid, GameObject item) {
            if (m_addList == null) {
                m_addList = new List<GameObject>();
            }
            if (contentList != null && contentList.ContainsKey(item._guid)) {
                Console.Out.WriteLine("Has contain guid: " + item._guid);
                return;
            }
            m_addList.Add(item);
        }

        public List<GameObject> GetAddList() {
            return m_addList;
        }

        /**
         * @brief add gameObjects in addList to UniqueList
         * 
         * invoked by gameEngine in adding phase
         * */
        public void UpdateAdd() {
            if (m_addList != null) {
                bool doSomething = false;
                foreach (GameObject gameObject in m_addList) {
                    gameObject.Initialize(Mgr<Scene>.Singleton);
                    base.AddItem(gameObject._guid, gameObject);
                    doSomething = true;
                }

                if (doSomething && Mgr<GameEngine>.Singleton._gameEngineMode
                            == GameEngine.GameEngineMode.MapEditor) {
                    Mgr<GameEngine>.Singleton.Editor.UpdateGameObjectList(this);
                }

                m_addList.Clear();
            }
        }

        /**
         * @brief release all gameObjects in the list
         * 
         * this should not be invoked while the scene is running
         * */
        public override void ReleaseAll() {
            base.ReleaseAll();
            if (Mgr<GameEngine>.Singleton._gameEngineMode
                == GameEngine.GameEngineMode.MapEditor) {
                Mgr<GameEngine>.Singleton.Editor.UpdateGameObjectList(this);
            }
        }

        /**
         * @brief remove a gameObject from list
         * 
         * the gameObject will be removed in next removing phase
         * */
        public override void RemoveItem(string guid) {
            if (m_removeList == null) {
                m_removeList = new List<GameObject>();
            }
            m_removeList.Add(contentList[guid]);

        }

        /**
         * @brief remove the gameObjects in removeList
         * 
         * invoked by gameEngine in removing phase
         * */
        public void UpdateRemove() {
            if (m_removeList != null) {
                bool doSomething = false;
                foreach (GameObject gameObject in m_removeList) {
                    contentList.Remove(gameObject._guid);
                    gameObject.Destroy();
                    doSomething = true;
                }

                if (doSomething && Mgr<GameEngine>.Singleton._gameEngineMode
                            == GameEngine.GameEngineMode.MapEditor) {
                    Mgr<GameEngine>.Singleton.Editor.UpdateGameObjectList(this);
                }

                m_removeList.Clear();
            }
        }

        /**
         * @brief update all gameObjects in game mode
         * 
         * invoked by gameEngine
         * */
        public void Update(int timeLastFrame) {
            if (contentList == null) {
                return;
            }

            foreach (KeyValuePair<string, GameObject> keyValue in contentList) {
                keyValue.Value.Update(timeLastFrame);
            }

        }

        /**
         * @brief update all gameObjects in editor mode
         * 
         * invoked by gameEngine
         * */
        public void EditorUpdate(int timeLastFrame) {
            if (contentList == null) {
                return;
            }

            foreach (KeyValuePair<string, GameObject> keyValue in contentList) {
                keyValue.Value.EditorUpdate(timeLastFrame);
            }
        }

        public bool SaveToNode(XmlNode node, XmlDocument doc) {
            XmlElement gameobjects = doc.CreateElement("GameObjects");
            node.AppendChild(gameobjects);

            if (contentList != null) {
                foreach (KeyValuePair<string, GameObject> keyValue in contentList) {
                    keyValue.Value.SaveToNode(gameobjects, doc);
                }
            }
            return true;
        }

        public static GameObjectList LoadFromNode(XmlNode node, Scene scene) {
            GameObjectList gameObjectList = new GameObjectList();
            foreach (XmlNode gameObject in node.ChildNodes) {
                GameObject newGameObject = GameObject.LoadFromNode(gameObject, scene);
                gameObjectList.AddItem(newGameObject._guid, newGameObject);
            }

            return gameObjectList;
        }
    }
}
